package org.needcoke.hs.okhttp;

import okhttp3.*;
import okio.Buffer;
import org.needcoke.hs.http.ContentType;
import org.needcoke.hs.http.HttpType;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 封装了OkHttp的请求
 *
 * @author warren
 */
public class OkHttpRequest implements org.needcoke.hs.http.Request {

    private Request request;

    public Request getRequest() {
        return request;
    }

    public OkHttpRequest(Request request) {
        this.request = request;
    }

    @Override
    public String getHost() {
        return request.url().host();
    }

    @Override
    public int getPort() {
        return request.url().url().getPort();
    }

    @Override
    public String getUrl() {
        return request.url().uri().toString();
    }

    @Override
    public String getUrlPrefix() {
        return (isHttps() ? "https" : "http") + "://" + request.url().host() + ":" + request.url().port();
    }

    @Override
    public void setUrlPrefix(String urlPrefix) {
        String url = urlPrefix + getPath() + QES + getQuery();
        this.request = this.request.newBuilder().url(url).build();
    }

    @Override
    public String getPath() {
        return request.url().encodedPath();
    }

    public String getQuery() {
        return request.url().query();
    }

    @Override
    public void setPath(String path) {
        setUrl(null, null, 0, path, null);
    }

    @Override
    public void setHost(String host) {
        setUrl(null, host, 0, null, null);
    }

    @Override
    public void setPort(int port) {
        setUrl(null, null, port, null, null);
    }

    @Override
    public boolean isHttps() {
        return request.isHttps();
    }

    @Override
    public String agreement() {
        return isHttps() ? "https" : "http";
    }

    @Override
    public void setUrl(String url) {
        this.request = request.newBuilder().url(url).build();
    }


    public void setUrl(String agg, String host, int port, String path, String query) {
        agg = null == agg ? agreement() : agg;
        host = null == host ? getHost() : host;
        port = 0 == port ? getPort() : port;
        path = null == path ? getPath() : path;
        query = null == query ? getQuery() : query;
        this.request = request.newBuilder().url(agg + "://" + host + ":" + port + path + "?" + query).build();
    }

    @Override
    public Map<String, String> getHeader() {
        Request copy = request.newBuilder().build();
        Map<String, String> headerMap = new HashMap<>();
        Headers headers = copy.headers();
        if (null != headers) {
            Set<String> names = headers.names();
            for (String name : names) {
                headerMap.put(name, headers.get(name));
            }
        }
        return headerMap;
    }

    @Override
    public void addHeader(String name, String value) {
        this.request = request.newBuilder().addHeader(name, value).build();
    }

    public String getHeader(String name) {
        Request copy = this.request.newBuilder().build();
        return copy.header(name);
    }

    @Override
    public Map<String, String> getUrlParameter() {
        String encodedQuery = request.url().query();
        String[] querys = encodedQuery.split(AND.toString());
        Map<String, String> queryMap = new HashMap<>();
        for (String query : querys) {
            String[] split = query.split(EQ.toString());
            queryMap.put(split[0], split[1]);
        }
        return queryMap;
    }

    @Override
    public ContentType getContentType() {
        RequestBody requestBody = request.body();
        MediaType mediaType = requestBody.contentType();
        String type = mediaType.toString();
        return ContentType.getContentTypeByValue(type);
    }

    @Override
    public HttpType getHttpType() {
        return HttpType.valueOf(request.method());
    }

    @Override
    public void setHttpType(HttpType httpType) {
        this.request = this.request.newBuilder().method(httpType.name(), request.body()).build();
    }

    @Override
    public Map<String, String> getFormParameter() {
        final Request copy = request.newBuilder().build();
        RequestBody body = copy.body();
        if (body instanceof FormBody) {
            FormBody formBody = (FormBody) body;
            Map<String, String> formMap = new HashMap<>();
            for (int i = 0; i < formBody.size(); i++) {
                formMap.put(formBody.name(i), formBody.value(i));
            }
            return formMap;
        }
        return null;
    }

    @Override
    public String getBody() {
        final Request copy = request.newBuilder().build();
        RequestBody body = copy.body();
        final Buffer buffer = new Buffer();
        try {
            copy.body().writeTo(buffer);
        } catch (IOException e) {
            return "something error,when show requestBody";
        }
        return buffer.readUtf8();
    }

    @Override
    public void setBody(String body, ContentType contentType) {
        Request.Builder builder = this.request.newBuilder();
        HttpType httpType = getHttpType();
        if (ContentType.JSON == contentType) {
            MediaType mediaType = MediaType.get(contentType.getValue());
            RequestBody requestBody = MultipartBody.create(body.getBytes(StandardCharsets.UTF_8), mediaType);
            builder.method(httpType.name(), requestBody);
        }
        this.request = builder.build();
    }

    @Override
    public void addUrlParameter(String name, String value) {
        String url = request.url().uri().toString();
        Character c = QES;
        if (url.contains(c.toString())) {
            c = AND;
        }
        this.request = request.newBuilder().url(url + c + name + EQ + value).build();
    }

    @Override
    public void addUrlParameter(Map<String, String> urlParameter) {
        Set<String> nameSet = urlParameter.keySet();
        String url = getUrl();
        String c = QES.toString();
        if (url.contains(c)) {
            c = AND.toString();
        }
        StringBuilder sb = new StringBuilder(url);
        for (String name : nameSet) {
            sb.append(c).append(name).append(EQ).append(urlParameter.get(name));
            c = AND.toString();
        }
        this.request = request.newBuilder().url(sb.toString()).build();
    }

    @Override
    public void rewriteUrlParameter(Map<String, String> urlParameter) {
        String url = getUrl();
        if (url.contains(QES.toString())) {
            url = url.split("\\?")[0];
        }
        String c = QES.toString();
        if (url.contains(c)) {
            c = AND.toString();
        }
        Set<String> nameSet = urlParameter.keySet();
        StringBuilder sb = new StringBuilder(url);
        for (String name : nameSet) {
            sb.append(c).append(name).append(EQ).append(urlParameter.get(name));
            c = AND.toString();
        }
        this.request = request.newBuilder().url(sb.toString()).build();
    }
}
